package message.visitor;

import java.io.IOException;

import message.Message;
import message.MessageParser;
import message.types.data.AddDataRequest;
import message.types.data.GetAllDatasAnswer;
import message.types.data.GetLastDataAnswer;
import message.types.message.RejectedRequest;
import message.types.none.GetAllDatasRequest;
import message.types.none.GetLastDataRequest;
import message.types.none.NewDataNotification;
import message.types.stalker.LogOffNotification;
import message.types.stalker.RegisterRequest;
import message.types.stalkerstring.GetRoomFromNameAnswer;
import message.types.stalkerstring.GetUserFromNameAnswer;
import message.types.string.CreatePrivatePersistentRoomRequest;
import message.types.string.CreateRoomRequest;
import message.types.string.GetRoomFromNameRequest;
import message.types.string.GetUserFromNameRequest;
import message.types.unique.EmptyMessage;
import message.types.unique.RoomInvitation;
import network.e2e.FrameWriter;
import stalker.Stalker;
import client.network.ServiceRequestCenter;

public class ClientMessageVisitor extends MessageVisitor<Void> {
  
  private final ServiceRequestCenter center_;
  private final FrameWriter writer_;
  
  public ClientMessageVisitor(ServiceRequestCenter center, FrameWriter writer) {
    assert (center != null && writer != null);
    center_ = center;
    writer_ = writer;
  }
  
  public void relayOverNet(Message message) {
    assert (message != null);
    try {
      MessageParser.send(message, writer_);
    } catch (IOException e) {
      System.out.println("Failed sending " + message);
    }
  }
  
  @Override
  public Void visit(AddDataRequest addDataReq) {
    assert (addDataReq != null);
    relayOverNet(addDataReq);
    return null;
  }

  @Override
  public Void visit(GetLastDataRequest getLastReq) {
    assert (getLastReq != null);
    relayOverNet(getLastReq);
    return null;
  }

  @Override
  public Void visit(GetLastDataAnswer getLastAns) {
    assert getLastAns != null;
    assert getLastAns.getDestination().equals(center_.getCredential());
    center_.receiveData(getLastAns.getClient(), getLastAns.getAnswer());
    return null;
  }

  @Override
  public Void visit(RegisterRequest getRegisterReq) {
    assert (getRegisterReq != null);
    relayOverNet(getRegisterReq);
    return null;
  }

  @Override
  public Void visit(EmptyMessage getEmptyMsg) {
    return null;
  }

  @Override
  public Void visit(CreateRoomRequest createRoomReq) {
    assert (createRoomReq != null);
    relayOverNet(createRoomReq);
    return null;
  }
  
  @Override
  public Void visit(CreatePrivatePersistentRoomRequest createRoomReq) {
    assert (createRoomReq != null);
    relayOverNet(createRoomReq);
    return null;
  }

  @Override
  public Void visit(RoomInvitation roomInvit) {
    assert roomInvit != null;
    assert roomInvit.getDestination().equals(center_.getCredential());
    center_.receiveInvitation(roomInvit.getInviter(), roomInvit.getLocation());
    return null;
  }

  @Override
  public Void visit(GetAllDatasRequest getAllData) {
    assert (getAllData != null);
    relayOverNet(getAllData);
    return null;
  }

  @Override
  public Void visit(GetAllDatasAnswer getAllAns) {
    assert getAllAns.getDestination().equals(center_.getCredential());
    center_.receiveDatas(getAllAns.getClient(), getAllAns.getAnswer());
    return null;
  }

  @Override
  public Void visit(GetUserFromNameRequest getStalkerFromName) {
    assert (getStalkerFromName != null);
    relayOverNet(getStalkerFromName);
    return null;
  }

  @Override
  public Void visit(GetUserFromNameAnswer getStalkerFromName) {
    assert getStalkerFromName.getDestination().equals(center_.getCredential());
    assert getStalkerFromName.getClient().equals(Stalker.USER_MANAGER);
    return null;
  }

  @Override
  public Void visit(NewDataNotification newDataNotif) {
    assert newDataNotif.getDestination().equals(center_.getCredential());
    // TODO?
    center_.requestUpdateRoom(newDataNotif.getClient());
    return null;
  }
  
  @Override
  public Void visit(LogOffNotification logOffNotif) {
    assert (logOffNotif != null);
    relayOverNet(logOffNotif);
    return null;
  }
  
  @Override
  public Void visit(GetRoomFromNameRequest get_stalker_from_name) {
    assert (get_stalker_from_name != null);
    relayOverNet(get_stalker_from_name);
    return null;
  }
  
  @Override
  public Void visit(GetRoomFromNameAnswer get_stalker_from_name) {
    assert get_stalker_from_name.getDestination().equals(center_.getCredential());
    assert get_stalker_from_name.getClient().equals(Stalker.ROOM_MANAGER_STALKER);
    return null;
  }

  @Override
  public Void visit(RejectedRequest rejectedRequest) {
    
    assert rejectedRequest != null;
    
    if (rejectedRequest.getDestination().equals(center_.getCredential())) {
      // message arrived
      center_.receiveRejectedMessage(rejectedRequest.getMessage());
    } else {
      relayOverNet(rejectedRequest);
    }
    
    return null;
  }

}
